/* boardmodel.cpp - this file is part of PixelMerge
 *
 * Copyright (C) 2010 Pascal Giard
 *
 * Author: Pascal Giard <evilynux@gmail.com>
 *
 * This file is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This file is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * Game logic.
 */

#include <stdlib.h>

#include "boardmodel.h"

#define NONE 65530

BoardModel::BoardModel(u16 nRows) {
  nbrRows = nRows;
  boardSize = nbrRows*nbrRows;
  pixels.resize(boardSize);

  // Set neighbors
  for(u16 i = 0; i < boardSize; i++) {
    // Top
    if(i < nbrRows) {
      pixels[i].neig[TOP] = NONE;
    } else {
      pixels[i].neig[TOP] = i - nbrRows;
    }
    // Down
    if(i > (boardSize-nbrRows-1)) {
      pixels[i].neig[DOWN] = NONE;
    } else {
      pixels[i].neig[DOWN] = i + nbrRows;
    }
    // Left
    if( (i%nbrRows) == 0 ) {
      pixels[i].neig[LEFT] = NONE;
    } else {
      pixels[i].neig[LEFT] = i - 1;
    }
    // Right
    if( ((i+1)%nbrRows) == 0 ) {
      pixels[i].neig[RIGHT] = NONE;
    } else {
      pixels[i].neig[RIGHT] = i + 1;
    }
  }
  this->newGame();
}

/** Nothing for now. */
BoardModel::~BoardModel() {}

void BoardModel::newGame() {
  // Generate random pixels
  srand(time(NULL));
  for(u16 i = 0; i < boardSize; i++) {
    pixels[i].color = rand() % NBR_PIXELS;
    pixels[i].group = false;
  }
  pixels[0].group = true; // Set root at topleft
  // Add neighbors of same color to group
  this->updateColor(pixels[0].color);
}

void BoardModel::updateColor(u8 color) {
  bool newNeig = true;

  // Change color for current members of the group
  for(u16 i = 0; i < boardSize; i++) {
    if( pixels[i].group ) {
      pixels[i].color = color;
    }
  }

  // Expand the group with neighbors now sharing the same color
  while(newNeig) {
    newNeig = false;
    for(u16 i = 0; i < boardSize; i++) {
      for(u8 j = 0; j < NBR_NEIGHBORS; j++ ) {
        u16 n = pixels[i].neig[j];
        if(n == NONE) {
          continue;
        }
        // We are not a current member of the group, neighbor is member of the
        // group and we share the same color
        if( !pixels[i].group and pixels[n].group and 
            pixels[n].color == pixels[i].color ) {
          pixels[i].group = true; // We are now part of the group
          // Visit other neighbors, perhaps they just became members too!
          newNeig = true;
        }
      }
    }
  }
}

// Is the game complete?
bool BoardModel::checkCompletion() {
  for(u16 i = 0; i < boardSize; i++) {
    if( !pixels[i].group ) {
      return false;
    }
  }
  return true;
}
